// 手写防抖函数

/**
 * 执行频率：在事件停止触发的延迟时间内执行一次
 * 
 * 防抖函数应用场景：
 * 1、频繁的点击按钮，触发某个事件
 * 2、监听浏览器滚动事件，完成某些特定操作
 * 3、用户缩放浏览器的resize事件等等
 * 
 * 目的：延迟执行，确保只在停止操作后执行一次
 * */

/**
 * @param {function} func - 目标对象
 * @param {number} wait - 防抖间隔时间
 * @param {boolean} immediate - 开启初次立即执行
 * @param {function} resultCallback - 目标对象返回值的回调函数
 * @return {function} - 防抖函数
 * @author m
 * @example
 *
 * ```js
 * const inputChange = function (event) {
 *   console.log(`发送了第${++counter}次网络请求`, this, event)
 *  // 返回值
 *  return "test"
 * }
 * 
 * const debounceChange = debounce(inputChange, 2000, false, (res) => {
 *  console.log("拿到真正执行函数的返回值:", res)
 * })
 * 
 * // 取消功能
 * const cancelBtn = document.querySelector("#cancel") // 获取取消按钮
 * cancelBtn.onclick = function() {
 *   debounceChange.cancel()
 * }
 * ```
 * 
 */

function debounce(func, wait = 200, immediate = false, resultCallback) {
  // 保存每次定时器操作，在下一次规定时间内 重复调用提供取消信息
  let timer = null;
  // 作为判断当前为立即执行 or 防抖模式
  let isInvoke = false;

  const _debounce = function (...args) {
    // 排除第一次调用无timer，其余规定时刻清除上一次定时器
    if (timer) clearTimeout(timer)

    if (immediate && !isInvoke) {
      const result = func.apply(this, args);
      // 将目标对象返回值返回后，能够进行回调执行处理
      if (resultCallback) resultCallback(result);
      // 初次立即执行，后续正常防抖模式
      isInvoke = true;
    } else {
      // 定时，正常防抖模式内容
      timer = setTimeout(() => {
        const result = func.apply(this, args) // 绑定this为元素本身以及event事件
        // 将目标对象返回值返回后，能够进行回调执行处理
        if (resultCallback) resultCallback(result);
        // 防抖模式结束，下次输入内容立即执行
        isInvoke = false;
      }, wait)
    }
  }

  // 封装取消功能
  _debounce.cancel = function () {
    if (timer) clearTimeout(timer);
    // 初始化
    timer = null;
    isInvoke = false;
  }

  return _debounce;
}



